我有分寸

[译文] GEM vs. TTM

gnawux gemgraphickernellinuxlwntranslation

By Jonathan Corbet
May 28, 2008
王旭于2008年8月8日译
http://lwn.net/Articles/283793/

在 Linux 下,即使是在有了基础硬件的编程接口信息的情况系,得到高性能的 3D 渲染仍然是非常具有挑战性的。这个问题的一个原因就是内存管理:一个 GPU 本质上说是一个拥有它自己的独立的内存的计算机系统。要想管理GPU 的内存 —— 以及以它的视角看到的系统内存,让系统能够跑起来就必须要小心,更不要说还要获得可接受的性能了。

不久以前,这个问题看上去要被翻译表映射(TTM)子系统 解决了。TTM 目前仍然没有进入主线内核,依赖于它的所有驱动自然也没有进入。最近的一个关于 TTM 如何才能进入主线的提问引发了一场有趣的讨论,最终使得局面急转直下,TTM 可能根本就不是未来的显存管理系统。

很多关于 TTM 的抱怨都已经浮现出来了。它的 API 远大于任意一个开源 Linux 驱动的需求;换句话说,大量的代码都是用于二进制发布的驱动的。隔离机制(fence, 管理 CPU 和 GPU 的并发性的机制)非常复杂而难于使用,而且并不是总能得到很好的性能。大量的使用内存映射缓冲会给它自己带来性能问题。TTM API 尝试着提供所有情况下的一切东西;结果对于很多开发者来说很难让特定的硬件去匹配这些 API,很难开始使用 TTM,也缺乏足够的灵活性。对于使用TTM的开源驱动来说,这是一个重大的不足。所以 Dave Airlie 担忧地说 :

现在,我希望有一个 radeon 或是什么新的驱动已经使用了 TTM,或者,至少有个 demo 展示了如何使用它,可是现在什么也没有,这让我很痛苦……真正的问题是 TTM 是不是真的适合于 Linux 桌面和嵌入式驱动的开发者们,至少我在桌面方面还没看到足够的正面反馈。

所有这些但有看来都是徒劳的,毕竟 TTM 已经在那了,而且也没有什么其他的替代品。然而,事情发生了,一个转机发生了,它就叫做图形执行管理器(这名字翻译的好难听阿,对不起观众了),简称 GEM。Intel 资助的 GEM 项目已经有一个月了(译注:原文写于08年5月底,目前 GEM 形势大好阿)。GEM 的开发者其实还没完全准备好来对外公布他们的工作,不过 TTM 的讨论让他们提前走上了前台。

Keith Packard (译注:Intel 的开源图形驱动项目的带头人)的 GEM 介绍 中包含了一个已有 API 的描述文档。GEM 在处理上面有很多显著不同。首先 GEM 使用普通、匿名、用户空间内存来用于分配图形缓冲对象。这意味着这些缓冲区可以在必要的时候被交换出物理内存。这个方法有其显著的优越性,不仅仅是内存使用的灵活性:它让挂起和恢复的实现可以直接通过恢复所有缓冲对象的方式自动完成了。

GEM API 尽量避免将缓冲区到用户空间的映射。映射工作代价高昂而且而且带来了 CPU 与 GPU 之间的缓存一致性问题。所以,GEM 用简单的 read() 和 write() 调用来取代映射,访问缓冲区对象。或者,至少,在 GEM 开发者能给每个缓冲对象附加一个文件描述符的时候的处理方法。而内核不会那么轻易管理这么多文件描述符,这样,实际的 API 使用了不同的缓冲对象 handle 和一系列的 ioctl() 调用。

也就是说,GEM可能映射一个缓冲对象到用户空间。不过,用户空间的驱动必须显示地承担管理缓存一致性的责任。为此,有一组 ioctl() 调用用于管理缓冲的“域”;所谓“域”,本质上说就是描述了系统中的哪个组件拥有这块缓冲区并有权操作它。改变一个缓冲的域(两类域,其一用于读访问,而另一个是写)将会进行必要的缓存刷新。在某种意义上说,这个机制重现了流 DMA API,DMA API 中的 DMA 缓冲区的所有权就可以在 CPU 和 外设控制器之间交换。不必惊讶,他们解觉得也是类似的问题。

GEM API 不需要显示的屏蔽 (fence) 操作。相反,当 CPU 操作需要访问缓冲区的时候,如果必要的话 CPU 就会简单地等待 GPU 完成对该缓冲区的操作。

最后,GEM API 并没有想要独自解决所有问题;很多重要操作(比如执行一组 GPU 指令)被留给硬件特定的驱动来实现了。GEM 本身在目前非常适于 Intel 驱动的需求;它不需要达到所有的 TTM 所有达到的目标。Eric Anholt 描述 到:

TTM 的问题是它要对所有硬件提供一套统一的 API,即使我们的驱动不希望这样的时候也是如此……我们尽量从另一个方面来达到这一目的:实现一个驱动。当其他人实现了另一个驱动,又发现这里面有些代码应该是公共的,那么就将它移动到支撑库里并共享它。

这种方法的有点是更容易来给 Intel 新加入一些东西。而且这可能是个好的开始,一组工作的驱动总比没有强。另一方面,这也意味着要让 GEM 支持其它硬件的驱动还需要大量的工作。对于这些工作如何去做,目前大概有两种观点:(1) GEM 为新的驱动的需求增加新的能力,或者 (2) 让驱动使用它自己的内存管理器。

第一种方法在很多情况下看起来更漂亮。但它也预示着 GEM API 会经常发生很多变化。这可能会延缓整个系统进入主线内核的脚步;GEM API 会输出到用户空间,所以必须保持变化的兼容性。看起来必须要不断演进的 API 会在快速的进入主线内核的时候受到阻力。

而对于第二种方法,Dave Airlie 给出了最好的解释 :

嗯,事情是我不能相信我们还不足够知道如何以一种通用的方法来做到这点,不过 TTM vs GEM 可能已经证明了这是不可能的了。那么我们可以赌一赌每个驱动一个内存管理器,不过我怀疑这将成为一个维护的噩梦,所以如果人们决定了这就是下一步要走的,我会很高兴地看到他发生。不过提交第 n+1 个内存管理器的人必须解事情出接口后面的机制,而且解释清楚为什么不能复用内存管理器 1 到 n。

一个还没被讨论过的问题就是性能。Keith Whitwell 给出了一组评分结果 ,该结果显示对于 i915 驱动,使用 TTM 或 GEM 的时候,性能会比不使用的情况显著降低。而 Keith Packard 的到了不同的结果 ,他的结果显示 GEM 驱动的性能明显更好。显然,目前需要一组一致的 benchmark;图形性能是重要的,但如果不能有效地测量也就没法优化。

使用匿名内存也会引起一些性能考虑:如果第一人称射击游戏 (FPS) 的血腥像素们要不停地被换页的话,体验可能就不尽如人意了。匿名内存可以位于高位内存,而且这样就不必使用32位指针来访问。一些 GPU 硬件不能访问高位内存;这将可能影响 kernel 的 bounce buffer (不好意思啊,这个不知道怎么翻译好了)。最后,GEM 还需要去证明它可以提供良好的性能,GEM的开发者们非常主动地使他们的硬件看起来很好,这也让工作在上面的东西有了一个更好的机会。(这句话翻译的比较晕)

所有这些能得到的结论是GPU的内存管理问题还不能简单认为是已经解决了。GEM可能最终称为这个答案,但它还是非常新的API,仍然需要大量的工作。这个领域中似乎还有很多的工作需要做。

(感谢 Timo Jyrinki 建议这个话题。)

gnawux
me!#$!@#$@#$wangxu!@#$%^&*()_me